package com.wuyan.web.auth.api;

import com.wuyan.web.auth.entity.PubAccount;
import com.wuyan.web.auth.entity.PubFunction;
import com.wuyan.web.auth.form.PubAccountRoleForm;
import com.wuyan.web.auth.form.RoleAuthForm;
import com.wuyan.web.auth.helper.AuthHelper;
import com.wuyan.web.auth.repo.PubAccountExtendRepo;
import com.wuyan.web.auth.service.IdentityService;
import com.wuyan.web.base.aop.ApiLogAnnotation;
import com.wuyan.web.base.helper.BaseApi;
import com.wuyan.web.base.helper.DataEncryptionHelper;
import com.wuyan.web.base.helper.auth.LoginInfo;
import com.wuyan.web.base.helper.convert.EncryptionUnReversibleConvert;
import com.wuyan.web.base.helper.rep.RepBody;
import com.wuyan.web.base.helper.rep.RepCodeEnum;
import com.wuyan.web.base.helper.rep.RepHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

import static com.wuyan.web.base.config.EntityConfig.DATA_ENCRYPTION;

/**
 * 授权相关
 */

@Slf4j
@RestController
@RequestMapping("/api")
public class IdentityApi extends BaseApi implements RepHelper {

    @Autowired
    private PubAccountExtendRepo pubAccountExtendRepo;

    @Autowired
    private IdentityService identityService;

    @Autowired
    private AuthHelper authHelper;

    /**
     * 对角色进行重新授权分配
     *
     * @param form 授权信息，包括菜单和接口
     * @param id   角色ID
     * @return RepBody<Boolean>
     */
    @PostMapping("/role/{id}")
    @ApiLogAnnotation(name = "Identity:roleCreate")
    public RepBody<Boolean> roleCreate(@RequestBody @Validated RoleAuthForm form, @PathVariable(value = "id") Integer id) throws Exception {
        return ok(identityService.roleCreate(id, form));
    }

    /**
     * 获取指定角色的已授权功能概要
     *
     * @param id 角色ID
     * @return RepBody<RoleAuthForm>
     */
    @GetMapping("/role/{id}/simple")
    @ApiLogAnnotation(name = "Identity:roleGetSimple")
    public RepBody<RoleAuthForm> roleGetSimple(@PathVariable(value = "id") Integer id) {
        RoleAuthForm roleAuthForm = identityService.roleGet(id);
        return ok(roleAuthForm);
    }

    /**
     * 对用户账户的角色进行重新分配
     *
     * @param form 授权信息
     * @param id   账户ID
     * @return RepBody<Boolean>
     */
    @PostMapping("/account/{id}")
    @ApiLogAnnotation(name = "Identity:accountCreate")
    public RepBody<Boolean> accountCreate(@RequestBody @Validated List<PubAccountRoleForm> form,
                                          @PathVariable(value = "id") Integer id)
            throws Exception {
        return ok(identityService.accountCreate(id, form));
    }

    /**
     * 临时授权：此操作会删除当前临时授权中相关的已授权角色记录
     *
     * @param form 临时授权信息
     * @param id   账户ID
     * @return RepBody<Boolean>
     */
    @PostMapping("/account/{id}/temp")
    @ApiLogAnnotation(name = "Identity:accountTempCreate")
    public RepBody<Boolean> accountTempCreate(@RequestBody @Validated List<PubAccountRoleForm> form,
                                              @PathVariable(value = "id") Integer id)
            throws Exception {
        return ok(identityService.accountTempCreate(id, form));
    }

    /**
     * 修改密码
     *
     * @param form 新密码和原有密码
     * @return RepBody<Boolean>
     */
    @PutMapping("/change-pwd")
    @ApiLogAnnotation(name = "Identity:changePwd")
    public RepBody<Boolean> changePwd(HttpServletRequest request,
                                      @RequestBody Map<String, Object> form)
            throws Exception {
        LoginInfo loginInfo = authHelper.get(request.getSession(), getAccessToken(request));
        if(null == loginInfo){
            return error(RepCodeEnum.ERR_LOGIN_EXPIRE);
        }

        String old = form.containsKey("pwd") ? form.get("pwd").toString() : "";
        if (!loginInfo.getAccount().getPassword().equals(EncryptionUnReversibleConvert.encode(old))) {
            return error(RepCodeEnum.ERR_LOGIN_PASSWORD);
        }

        String ak = form.containsKey("ak") ? form.get("ak").toString() : "";
        String code = getAttr(request, "resetPwd-" + ak, String.class, true);

        if (null == code) {
            return error(RepCodeEnum.ERR_LOGIN_VERIFY_INVALID);
        }
        if (!code.equals(form.get("code").toString().toUpperCase())) {
            return error(RepCodeEnum.ERR_LOGIN_VERIFY);
        }

        String password = form.containsKey("newPwd") ? form.get("newPwd").toString() : "";

        Optional<PubAccount> optionalPubAccount =
                pubAccountExtendRepo.findById(loginInfo.getAccount().getId());
        if (!optionalPubAccount.isPresent()) {
            return error(RepCodeEnum.ERR_LOGIN_USERNAME);
        }
        PubAccount pubAccount = optionalPubAccount.get();

        // 需要加密
        pubAccount.setPassword(password);
        DataEncryptionHelper.encode("pubAccount", pubAccount, DATA_ENCRYPTION);
        pubAccountExtendRepo.save(pubAccount);

        return ok(true);
    }

    /**
     * 获取当前登录账户下所有的已授权菜单
     *
     * @param request 请求体
     * @return RepBody<List < PubRole>>
     * @throws IOException e
     */
    @GetMapping("/menu")
    @ApiLogAnnotation(name = "Identity:menu")
    public RepBody<List<PubFunction>> getMenu(HttpServletRequest request) throws IOException {
        LoginInfo loginInfo = authHelper.get(request.getSession(), getAccessToken(request));
        if(null == loginInfo){
            return error(RepCodeEnum.ERR_LOGIN_EXPIRE);
        }

        List<PubFunction> data = identityService.getMenu(loginInfo);

        return ok(data);
    }


    // ======================================----------====================================== //
    //                                         新的api                                         //
    // ======================================----------====================================== //

    /**
     * 新增角色
     *
     * @param id    用户ID
     * @param roles 角色ID
     * @return RepBody<Boolean>
     */
    @PostMapping("/role/add/{id}")
    @ApiLogAnnotation(name = "Identity:roleCreate")
    public RepBody<Boolean> roleAdd(@PathVariable(value = "id") Integer id,
                                    @RequestBody Integer[] roles) {

        Optional<PubAccount> accountOptional = pubAccountExtendRepo.findById(id);

        if (!accountOptional.isPresent()) {
            return error(RepCodeEnum.ERR_LOGIN_USERNAME);
        }

        assert null != roles && roles.length > 0 : "新增角色不能为空";

        PubAccount pubAccount = accountOptional.get();
        String role = pubAccount.getRole();

        // 需要判断是否已有角色
        if (StringUtils.isBlank(role)) {
            pubAccount.setRole(StringUtils.join(roles));
        } else {
            Set<Integer> setRole = Arrays.stream(roles).collect(Collectors.toSet());
            String[] split = role.split(",");
            setRole.addAll(Arrays.stream(split).map(Integer::parseInt).collect(Collectors.toSet()));
            pubAccount.setRole(StringUtils.join(split));
        }

        pubAccountExtendRepo.save(pubAccount);

        return ok(true);
    }

}
